#include <iostream>
#include <cstdlib>
#include <cassert>
using namespace std;

#include "Card.h"
#include "Deck.h"
#include "PokerHand.h"

const int PokerHand::CARD_NUM[PokerHand::NUMRANKS] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1};

PokerHand::PokerHand(){
	numInHand = 0;
}

PokerHand::PokerHand(Deck & deck){
	dealAll(deck);
	numInHand = 5;
}

PokerHand::PokerHand(const Card & c1,       // Create a hand explictly from five
            const Card & c2,       //   individual cards
            const Card & c3, 
            const Card & c4,
            const Card & c5){
	hand[0] = c1;
	hand[1] = c2;
	hand[2] = c3;
	hand[3] = c4;
	hand[4] = c5;
	numInHand = 5;	
}

void PokerHand::dealAll(Deck & deck){
	for (int i=0; i<5 ; i++){
		hand[i] = deck.dealCard();
		numInHand++;
	}
}

void PokerHand::dealOne(Deck & deck){
	hand[numInHand] = deck.dealCard();
	numInHand++;
}

void PokerHand::reset(){
	numInHand = 0;
}

Card PokerHand::getCard(int index) const{
	return hand[index];
}

Card::Suit PokerHand::getCardSuit(int index) const{
	return hand[index].getSuit();
}

int PokerHand::getCardRank(int index) const{
	return hand[index].getRank();
}

void PokerHand::rankCount(int * counts) const{
}

void PokerHand::evalHand(){
  int rank, suit;
  int numConsec = 0;

  royalFlush = false;
  straight = false;
  flush = false;
  four = false;
  three = false;
  pairs = 0;
  highVal = 0;

  for (rank = 0; rank < NUMRANKS; rank++)
		numInRank[rank] = 0;
  for (suit = 0; suit < NUMSUITS; suit++)
    	numInSuit[suit] = 0;

  for (int i=1; i <= numInHand; i++){
	// shift rankCount
	int idx;
	if (hand[i-1].getRank() == 1)
		idx = 12;
	else
		idx = hand[i-1].getRank() - 2;
		
	numInRank[idx]++;
	numInSuit[hand[i-1].getSuit()]++;
  }

  for (suit = 0; suit < NUMSUITS; suit++){
    if (numInSuit[suit] == COUNT)
      flush = true;
	//cout << numInSuit[suit] << ",";
  }
  //cout << endl;

   for (rank = 0; rank < NUMRANKS; rank++){
	 //cout << numInRank[rank] << ",";
     if (numInRank[rank] == 0)
       numConsec = 0;
     else
     {
       numConsec++;

       if (numConsec == COUNT)
       {
		  highVal = rank;
          straight = true;
            if (rank == (NUMRANKS-1) && flush)
            	royalFlush = true;
       }
     }
  }
  //cout << endl;

  for (rank = 0; rank < NUMRANKS; rank++)
  {
    if (numInRank[rank] == 4){
            four = true;
			highVal = rank;
	}
    if (numInRank[rank] == 3){
            three = true;
			highVal = rank;
	}
    if (numInRank[rank] == 2){
            pairs++;
			highVal = rank;
	}
  }
}

void PokerHand::showHand(){
  if (royalFlush)    
     cout << "Royal Flush" << endl;
  else if (straight && flush)      
     cout << "Straight Flush" << endl;
  else if (four)        
     cout << "Four of a Kind:" << CARD_NUM[highVal] << endl;
  else if (three && pairs == 1)  
     cout << "Full House" << endl;
  else if (flush)        
     cout << "Flush" << endl;
  else if (straight)    
    cout << "Straight" << endl;
  else if (three)        
    cout << "Three of a Kind:" << CARD_NUM[highVal] << endl;
  else if (pairs == 2)  
    cout << "Two Pair" << endl;
  else if (pairs == 1)  
    cout << "One Pair:" << CARD_NUM[highVal] << endl;
  else{         
  	for (int rank = 0; rank < NUMRANKS; rank++)
  	{
		if (numInRank[rank] == 1)
			highVal = rank;
	}
    cout << "High Card:" << CARD_NUM[highVal] << endl;
  }
}

bool PokerHand::isRoyalFlush() const{
	return royalFlush;
}
bool PokerHand::isStraightFlush() const{
	return straight && flush;
}
int  PokerHand::isFourOfKind() const{
	if (four)
		return (CARD_NUM[highVal]);
	else
		return 0;
}
bool PokerHand::isFullHouse() const{
	return (three && pairs == 1);
}
bool PokerHand::isFlush() const{
	return flush;
}
int  PokerHand::isStraight() const{
	if (straight)
		return (CARD_NUM[highVal]);
	else
		return 0;
}
int  PokerHand::isThreeOfKind() const{
	if (three)
		return (CARD_NUM[highVal]);
	else
		return 0;
}
bool PokerHand::isTwoPair() const{
	return (pairs == 2);
}
int PokerHand::isOnePair() const{
	if (pairs == 1)
		return (CARD_NUM[highVal]);
	else
		return 0;
}

string PokerHand::toString() const{
	string tmp;
	for (int i=0; i<numInHand; i++){
		tmp += hand[i].toString() + " ";
	}
	return tmp;
}
void PokerHand::print() const{
	cout << toString() << endl;
}